<template>
	<div :class="{
      'message-input-audio': true,
      'message-input-audio-open': isAudioTouchBarShow,
    }">
		<Icon class="audio-message-icon" :file="props.isEnableAudio ? textIcon : audioIcon" :size="'23px'"
			:hotAreaSize="'3px'" @onClick="switchAudio" />
		<view v-if="props.isEnableAudio" class="audio-input-touch-bar" @touchstart="handleTouchStart"
			@longpress="handleLongPress" @touchmove="handleTouchMove" @touchend="handleTouchEnd">
			<span>{{ TUITranslateService.t(`TUIChat.${touchBarText}`) }}</span>
			<view v-if="isRecording" class="record-modal">
				<div class="red-mask" />
				<view class="float-element moving-slider" />
				<view class="float-element modal-title">
					{{ TUITranslateService.t(`TUIChat.${modalText}`) }}
				</view>
			</view>
		</view>
	</div>
</template>

<script setup lang="ts">
	import { ref, onMounted, onUnmounted } from '../../../adapter-vue';
	import {
		TUIStore,
		StoreName,
		TUIChatService,
		SendMessageParams,
		IConversationModel,
		TUITranslateService,
	} from '@tencentcloud/chat-uikit-engine';
	import { TUIGlobal } from '@tencentcloud/universal-api';
	import Icon from '../../common/Icon.vue';
	import audioIcon from '../../../assets/talkImage/talk.png';
	import textIcon from '../../../assets/talkImage/text.png';
	import { Toast, TOAST_TYPE } from '../../common/Toast/index';
	import { throttle } from '../../../utils/lodash';
	import { isEnabledMessageReadReceiptGlobal } from '../utils/utils';
	import { InputDisplayType } from '../../../interface';

	interface IProps {
		isEnableAudio : boolean;
	}

	interface IEmits {
		(e : 'changeDisplayType', type : InputDisplayType) : void;
	}

	interface RecordResult {
		tempFilePath : string;
		duration ?: number;
		fileSize ?: number;
	}

	type TouchBarText = '按住说话' | '抬起发送' | '抬起取消';
	type ModalText = '正在录音' | '继续上滑可取消' | '松开手指 取消发送';

	const emits = defineEmits<IEmits>();
	const props = withDefaults(defineProps<IProps>(), {
		isEnableAudio: false,
	});

	let recordTime : number = 0;
	let isManualCancelBySlide = false;
	let recordTimer : number | undefined;
	let firstTouchPageY : number = -1;
	let isFingerTouchingScreen = false;
	let isFirstAuthrizedRecord = false;
	const recorderManager = TUIGlobal?.getRecorderManager();

	const isRecording = ref(false);
	const touchBarText = ref<TouchBarText>('按住说话');
	const modalText = ref<ModalText>('正在录音');
	const isAudioTouchBarShow = ref<boolean>(false);
	const currentConversation = ref<IConversationModel>();

	const recordConfig = {
		// Duration of the recording, in ms, with a maximum value of 600000 (10 minutes)
		duration: 60000,
		// Sampling rate
		sampleRate: 44100,
		// Number of recording channels
		numberOfChannels: 1,
		// Encoding bit rate
		encodeBitRate: 192000,
		// Audio format
		// Select this format to create audio messages that can be interoperable across all chat platforms (Android, iOS, WeChat Mini Programs, and Web).
		format: 'mp3',
	};

	function switchAudio() {
		emits('changeDisplayType', props.isEnableAudio ? 'editor' : 'audio');
	}

	onMounted(() => {
		// Register events for the audio recording manager
		recorderManager.onStart(onRecorderStart);
		recorderManager.onStop(onRecorderStop);
		recorderManager.onError(onRecorderError);

		TUIStore.watch(StoreName.CONV, {
			currentConversation: onCurrentConverstaionUpdated,
		});
	});

	onUnmounted(() => {
		TUIStore.unwatch(StoreName.CONV, {
			currentConversation: onCurrentConverstaionUpdated,
		});
	});

	function onCurrentConverstaionUpdated(conversation : IConversationModel) {
		currentConversation.value = conversation;
	}

	function initRecorder() {
		initRecorderData();
		initRecorderView();
	}

	function initRecorderView() {
		isRecording.value = false;
		touchBarText.value = '按住说话';
		modalText.value = '正在录音';
	}

	function initRecorderData(options ?: { hasError : boolean }) {
		clearInterval(recordTimer);
		recordTimer = undefined;
		recordTime = 0;
		firstTouchPageY = -1;
		isManualCancelBySlide = false;
		if (!options?.hasError) {
			recorderManager.stop();
		}
	}

	function handleTouchStart() {
		if (isFingerTouchingScreen) {
			// Compatibility: Ignore the recording generated by the user's first authorization on the APP.
			isFirstAuthrizedRecord = true;
		}
	}

	function handleLongPress() {
		isFingerTouchingScreen = true;
		recorderManager.start(recordConfig);
	}

	const handleTouchMove = throttle(function (e) {
		if (isRecording.value) {
			const pageY = e.changedTouches[e.changedTouches.length - 1].pageY;
			if (firstTouchPageY < 0) {
				firstTouchPageY = pageY;
			}
			const offset = (firstTouchPageY as number) - pageY;
			if (offset > 150) {
				touchBarText.value = '抬起取消';
				modalText.value = '松开手指 取消发送';
				isManualCancelBySlide = true;
			} else if (offset > 50) {
				touchBarText.value = '抬起发送';
				modalText.value = '继续上滑可取消';
				isManualCancelBySlide = false;
			} else {
				touchBarText.value = '抬起发送';
				modalText.value = '正在录音';
				isManualCancelBySlide = false;
			}
		}
	}, 100);

	function handleTouchEnd() {
		isFingerTouchingScreen = false;
		recorderManager.stop();
	}

	function onRecorderStart() {
		if (!isFingerTouchingScreen) {
			// If recording starts but the finger leaves the screen,
			// it means that the initial authorization popup interrupted the recording and it should be ignored.
			isFirstAuthrizedRecord = true;
			recorderManager.stop();
			return;
		}
		recordTimer = setInterval(() => {
			recordTime += 1;
		}, 1000);
		touchBarText.value = '抬起发送';
		isRecording.value = true;
	}

	function onRecorderStop(res : RecordResult) {
		if (isFirstAuthrizedRecord) {
			// Compatibility: Ignore the recording generated by the user's first authorization on WeChat. This is not applicable to the APP.
			isFirstAuthrizedRecord = false;
			initRecorder();
			return;
		}
		if (isManualCancelBySlide || !isRecording.value) {
			initRecorder();
			return;
		}
		clearInterval(recordTimer);
		/**
		 * Compatible with uniapp for building apps
		 * Compatible with uniapp voice messages without duration
		 * Duration and fileSize need to be supplemented by the user
		 * File size = (Audio bitrate) * Length of time (in seconds) / 8
		 * res.tempFilePath stores the temporary path of the recorded audio file
		*/
		const tempFilePath = res.tempFilePath;
		const duration = res.duration ? res.duration : recordTime * 1000;
		const fileSize = res.fileSize ? res.fileSize : ((48 * recordTime) / 8) * 1024;

		if (duration < 1000) {
			Toast({
				message: '录音时间太短',
				type: TOAST_TYPE.NORMAL,
				duration: 1500,
			});
		} else {
			const options = {
				to:
					currentConversation?.value?.groupProfile?.groupID
					|| currentConversation?.value?.userProfile?.userID,
				conversationType: currentConversation?.value?.type,
				payload: { file: { duration, tempFilePath, fileSize } },
				needReadReceipt: isEnabledMessageReadReceiptGlobal(),
			} as SendMessageParams;
			TUIChatService?.sendAudioMessage(options);
		}
		initRecorder();
	}

	function onRecorderError() {
		initRecorderData({ hasError: true });
		initRecorderView();
	}
</script>

<style lang="scss" scoped>
	@import "../../../assets/styles/common";

	.message-input-audio {
		display: flex;
		flex-direction: row;
		align-items: center;

		.audio-message-icon {
			margin-right: 3px;
		}

		.audio-input-touch-bar {
			height: 39px;
			flex: 1;
			border-radius: 8px;
			display: flex;
			flex-direction: row;
			justify-content: center;
			align-items: center;
			background-color: #F5F6F7;
			font-weight: 400;
			font-size: 32rpx;
			color: #333333;

			.record-modal {
				height: 300rpx;
				width: 60vw;
				background-color: rgba(0, 0, 0, 0.8);
				position: fixed;
				left: 50%;
				top: 50%;
				transform: translate(-50%, -50%);
				z-index: 9999;
				border-radius: 24rpx;
				display: flex;
				flex-direction: column;
				overflow: hidden;

				.red-mask {
					position: absolute;
					inset: 0;
					background-color: rgba(#ff3e48, 0.5);
					opacity: 0;
					transition: opacity 10ms linear;
					z-index: 1;
				}

				.moving-slider {
					margin: 10vw;
					width: 40rpx;
					height: 16rpx;
					border-radius: 4rpx;
					background-color: #006fff;
					animation: loading 1s ease-in-out infinite alternate;
					z-index: 2;
				}

				.float-element {
					position: relative;
					z-index: 2;
				}
			}

			@keyframes loading {
				0% {
					transform: translate(0, 0);
				}

				100% {
					transform: translate(30vw, 0);
					background-color: #f5634a;
					width: 40px;
				}
			}

			.modal-title {
				text-align: center;
				color: #fff;
			}
		}

		&-open {
			flex: 1;
		}
	}
</style>